iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
AI & Data

Fast ai 30天系列 第 17

協同過濾(二)

  • 分享至 

  • xImage
  •  

創建模型

承接昨天的code

為了怕忘記,先說明dls 是什麼
https://ithelp.ithome.com.tw/upload/images/20231002/20110579SD84ZhIxdV.png

class DotProduct(Module):
    def __init__(self, n_users, n_movies, n_factors):
        self.user_factors = Embedding(n_users, n_factors)
        self.movie_factors = Embedding(n_movies, n_factors)
        
    def forward(self, x):
        users = self.user_factors(x[:,0])
        movies = self.movie_factors(x[:,1])
        return (users * movies).sum(dim=1)

這個 class 的名字 "DotProduct" 代表了一個模型,用於電影推薦。它的主要功能是進行用戶對電影的評分預測,通過計算用戶嵌入和電影嵌入之間的內積。這個模型可以使用參數 n_users、n_movies 和 n_factors 來建立。當調用其中的 "forward" 方法時,它會接受一個包含用戶和電影信息的輸入張量 x,然後對這些信息進行嵌入,計算內積,最終回傳評分的預測結果。
現在只寫了forward ,後面應該還要補充其他方法
以下是使用這個類別建立一個物件,取名叫model,然後把他傳入fastai.Learner類別中建立Learner物件
取名為learn,然後跑5個epoch, learning rate設定為5e-3

model = DotProduct(n_users, n_movies, 50)
learn = Learner(dls, model, loss_func=MSELossFlat())
learn.fit_one_cycle(5, 5e-3)

https://ithelp.ithome.com.tw/upload/images/20231002/201105795I2GTnumgw.png
fit_one_cycle 我又忘記了,再註記一下:
1cycle policy 的學習率調整策略:
這個策略的主要思想是在訓練過程中逐漸增加學習率,然後再逐漸降低學習率,以加速模型的收斂,同時防止過度擬合。
通常包括以下步驟:
以較低的學習率開始訓練
然後逐漸提高學習率,直到達到一個最大值。
接下來,再逐漸降低學習率,直到訓練結束。
這種策略的目標是在開始時快速收斂,然後在訓練過程中進一步調整以提高模型的性能。使用 fit_one_cycle 方法,就可以輕鬆實現這種策略,而不必手動調整學習率。這也是與pytorchd的OneCycleLR最大差別

好這不是重點,因為我們其實是要看協同過濾是怎麼做的。
上這門課的問題就是初學者(像我),就會常常被小動作帶偏,而搞不清楚最終目標是什麼。
所以要練習看不懂的先搞懂這一大段的「目的」是什麼,先看效果,中間弄不懂的東西或是小技巧,等第二遍再來弄懂

那現在講師用自創的內積算法,做了一個model ,然後拿來跑,顯然結果不怎麼好
那該如何改進呢?
首先講師說到我們的模型,缺少了偏見這個參數
也就是說我們的編碼頂多可以說明這部電影多科幻,多老、動作成份有多少,而不能說明人們有多喜歡他,
一但有人特別積級評分,或是特別消積評分,可能會讓我們的模型有較大的偏差
所以這邊就要加入bias
所以我們的內積模型可以修改如下

class DotProductBias(Module):
    def __init__(self, n_users, n_movies, n_factors, y_range=(0,5.5)):
        self.user_factors = Embedding(n_users, n_factors)
        self.user_bias = Embedding(n_users, 1)
        self.movie_factors = Embedding(n_movies, n_factors)
        self.movie_bias = Embedding(n_movies, 1)
        self.y_range = y_range
        
    def forward(self, x):
        users = self.user_factors(x[:,0])
        movies = self.movie_factors(x[:,1])
        res = (users * movies).sum(dim=1, keepdim=True)
        res += self.user_bias(x[:,0]) + self.movie_bias(x[:,1])
        return sigmoid_range(res, *self.y_range)

可以看到user 多了bias,movie 也多了bias
還多了一個y_range表示模型的輸出應該落在的範圍,通常用於回歸問題。
forward 中,res 一樣要先做內建,但是最後再加上user 及movie 的bias
最後應用 sigmoid_range 函數,將輸出限制在指定的 y_range 範圍內,這通常用於回歸問題,確保輸出在合理的範圍內。

設定完再跑一次看看結果,有沒有更好?

https://ithelp.ithome.com.tw/upload/images/20231002/20110579ykvusqNczZ.png

結果變更爛了!!
我們可以觀察,發現在train 的loss 持續下降,而valid 卻幾乎沒什麼降,最後反而上升
這可能存在潛在的過擬合現象。

所以這邊講師提供了一種方法來決解這個氣現象:權重衰減(weight decay)

也就是L2正則化

先來觀察一下為什麼要加入權重衰減
看一下以下的code 及圖
https://ithelp.ithome.com.tw/upload/images/20231002/20110579qmmdRo6Fhw.png

這張圖說明了如果在計算梯度時,沒有加入正則化的話
則這個受某係數影響很大,如圖中的a
a 越大則圖越窄,容易落入局部最小值

所以我此時我們加入一個「權重平方和」就可以改善此現象
loss_with_wd = loss + wd * (parameters**2).sum()

但計算平方的話蠻消耗資源,還好我們知道微分的話,指數會變系數剩到變數上,所以平方就會變成2x
parameters.grad += wd * 2 * parameters

看一下改進後的code 還有執行結果

https://ithelp.ithome.com.tw/upload/images/20231002/20110579Sxz5uS9gyN.png

much better ? 我看來只有好一點🤣,但這個例子就到這邊。顯然我們還有很多可以改進的地方

接下來就要講 Creating Our Own Embedding Module 了,但這就到另一個影片去了

下一篤待續


上一篇
協同過濾(一)
下一篇
CNN(一)
系列文
Fast ai 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言